#ifndef _BLKIO_H
#define _BLKIO_H

#include <ds/list.h>
#include <ds/parted_buffer.h>
#include <ds/waitq.h>
#include <ds/mutex.h>
#include <device/device.h>

#include <type.h>

#define BLKIO_WRITE 0x1
#define BLKIO_ERROR 0x2

#define BLKIO_BUSY 0x4
#define BLKIO_PENDING 0x8

#define BLKIO_WAIT 0x1

#define BLKIO_FREE 0x10

#define BLKIO_SCHED_IDEL 0x1

typedef struct block_device_io_request blkio_req_t;
typedef struct block_device_io_context blkio_ctx_t;

typedef void (io_req_handler)(blkio_req_t* req);
typedef void (io_complete)(blkio_req_t* req);
typedef bool (io_is_req_done)(void* data);

typedef struct block_device_io_request {
    lnode_t reqs;
    waitq_t wait;
    blkio_ctx_t* io_ctx;
    pbuffer_t* pb;
    u32 flags;
    u64 blk_addr;
    int errcode;
    void* track_data;
    io_is_req_done* is_req_done;
} blkio_req_t;

typedef struct block_device_io_context {
    lnode_t queue;
    u32 state;
    u32 busy;
    void* driver;
    io_req_handler* req_handle;
    mutex_t lock;
} blkio_ctx_t;

void blkio_init();

blkio_req_t* blkio_read_req(pbuffer_t* pb, u64 start_lba, u32 opt);

blkio_req_t* blkio_write_req(pbuffer_t* pb, u64 start_lba, u32 opt);

void blkio_free_req(blkio_req_t* req);

void blkio_commit(blkio_ctx_t* ctx, blkio_req_t* req, int options);

void blkio_schedule(blkio_ctx_t* ctx);

void blkio_complete(blkio_req_t* req);

blkio_ctx_t* blkio_newctx(io_req_handler handler);

int blkpart_probe(device_t* dev);

#endif /* _BLKIO_H */